package com.atguigu.java.ai.langchain4j.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.read.listener.PageReadListener;
import com.atguigu.java.ai.langchain4j.entity.SystemData;
import com.atguigu.java.ai.langchain4j.service.Neo4jService;
import org.jgrapht.Graph;
import org.jgrapht.graph.DefaultDirectedGraph;
import org.jgrapht.graph.DefaultEdge;
import org.neo4j.driver.*;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;

import java.util.*;

import static org.bson.assertions.Assertions.assertNotNull;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * Neo4j 服务实现类，负责处理与 Neo4j 数据库相关的操作，包括数据导入、图构建等。
 */
@Service
public class Neo4jServiceImpl implements Neo4jService {

    /**
     * Neo4j 数据库驱动实例，用于与数据库进行交互。
     */
    private final Driver driver;

    /**
     * Neo4j 数据库的连接 URI。
     */
    // 配置信息提取为字段
    private final String url = "neo4j://10.211.55.4:7687";
    /**
     * 连接 Neo4j 数据库的用户名。
     */
    private final String username = "neo4j";
    /**
     * 连接 Neo4j 数据库的密码。
     */
    private final String password = "neo4j123";

    /**
     * 构造函数，初始化 Neo4j 数据库驱动。
     */
    public Neo4jServiceImpl() {
        // 使用配置的 URI、用户名和密码创建数据库驱动实例
        this.driver = GraphDatabase.driver(url, AuthTokens.basic(username, password));
    }

    /**
     * 导入文件数据到 Neo4j 数据库。
     *
     * @param file 上传的文件，包含需要导入的数据。
     * @throws Exception 如果文件处理或数据库操作过程中发生错误。
     */
    @Override
    public void importData(MultipartFile file) throws Exception {
        // 检查上传的文件是否为空
        if (file.isEmpty()) {
            throw new IllegalArgumentException("上传的文件为空");
        }
        // 创建临时文件用于存储上传的文件内容
        File tempFile = File.createTempFile("temp", ".xls");
        // 将上传的文件内容传输到临时文件
        file.transferTo(tempFile);
        try {
            // 使用 EasyExcel 读取临时文件中的数据
            List<SystemData> dataList = readExcelWithEasyExcel(tempFile.getAbsolutePath());
            // 确保读取的数据列表不为空
            assertNotNull(dataList);
            // 根据读取的数据构建图结构
            Graph<String, DefaultEdge> graph = buildGraph(dataList);
            // 将构建好的图导入到 Neo4j 数据库中
            importGraphToNeo4j(graph, dataList);
        } finally {
            // 删除临时文件
            tempFile.delete();
            // 关闭数据库驱动连接
            close();
        }
    }

    /**
     * 读取 Excel 数据并跳过前三行。
     *
     * @param filePath Excel 文件的绝对路径。
     * @return 读取到的系统数据列表，如果文件不存在或数据不足则返回空列表。
     */
    @Override
    public List<SystemData> readExcelWithEasyExcel(String filePath) {
        // 存储读取到的系统数据
        List<SystemData> dataList = new ArrayList<>();

        System.out.println("📁 正在读取文件: " + filePath);
        // 检查文件是否存在
        if (!new File(filePath).exists()) {
            System.err.println("❌ 文件不存在，请检查路径");
            return Collections.emptyList();
        }

        // 使用 EasyExcel 读取文件数据，并将数据添加到 dataList 中
        EasyExcel.read(filePath, SystemData.class, new PageReadListener<SystemData>(dataList::addAll))
                .sheet()
                .doRead();

        System.out.println("📄 原始读取到的数据条数: " + dataList.size());

        // 如果数据条数大于 3 条，则跳过前三行
        if (dataList.size() > 3) {
            return dataList.subList(3, dataList.size());
        } else {
            System.err.println("⚠️ 数据不足 3 条，返回全部数据");
            return dataList;
        }
    }

    /**
     * 根据系统数据列表构建图结构。
     *
     * @param dataList 系统数据列表。
     * @return 构建好的有向图。
     */
    @Override
    public Graph<String, DefaultEdge> buildGraph(List<SystemData> dataList) {
        // 创建一个有向图实例
        Graph<String, DefaultEdge> graph = new DefaultDirectedGraph<>(DefaultEdge.class);
        // 存储需求维度的信息
        Map<String, Map<String, Object>> demandInfoDict = new HashMap<>();
        // 存储系统维度的信息
        Map<String, Map<String, Object>> systemInfoDict = new HashMap<>();

        // 遍历系统数据列表，填充需求和系统维度的信息
        for (SystemData data : dataList) {
            String systemName = data.getSystemName();
            String demandNo = data.getDemandNo();
            String demandName = data.getDemandTitle();
            String changeContent = data.getChangeContent();
            String isMainSystem = data.getIsMainSystem();
            String systemLayer = data.getSystemLayer();
            String systemArea = data.getSystemArea();
            String systemBelongDepartment = data.getSystemBelongDepartment();
            String systemManager = data.getSystemManager();
            String systemNo = data.getSystemNo();
            String reportDate = data.getReportDate();

            // 需求维度
            demandInfoDict.computeIfAbsent(demandNo, k -> new HashMap<String, Object>() {{
                put("demand_name", demandName);
                put("change_content", new ArrayList<String>());
                put("main_system", "");
                put("related_systems", new ArrayList<String>());
            }});
            // 如果当前系统是主系统，则更新需求信息中的主系统字段
            if ("是".equals(isMainSystem)) {
                demandInfoDict.get(demandNo).put("main_system", systemName);
            }
            // 将变更内容添加到需求信息中的变更内容列表中
            ((List<String>) demandInfoDict.get(demandNo).get("change_content")).add(changeContent);
            // 完善 related_systems 更新逻辑
            List<String> relatedSystems = (List<String>) demandInfoDict.get(demandNo).get("related_systems");
            if (!relatedSystems.contains(systemName)) {
                relatedSystems.add(systemName);
            }

            // 系统维度
            systemInfoDict.computeIfAbsent(systemName, k -> new HashMap<String, Object>() {{
                put("demand_no", new ArrayList<String>());
                put("demand_info", new ArrayList<String>());
                put("change_content", new ArrayList<String>());
                put("change_count", 0);
                put("main_req_count", 0);
                put("related_req_count", 0);
                put("system_layer", systemLayer);
                put("system_area", systemArea);
                put("system_belong_department", systemBelongDepartment);
                put("system_manager", systemManager);
                put("system_no", systemNo);
                put("report_date", reportDate);
            }});
            ((List<String>) systemInfoDict.get(systemName).get("demand_no")).add(demandNo);
            ((List<String>) systemInfoDict.get(systemName).get("change_content")).add(changeContent);
            int changeCount = (int) systemInfoDict.get(systemName).get("change_count") + 1;
            systemInfoDict.get(systemName).put("change_count", changeCount);
            if ("是".equals(isMainSystem)) {
                // 如果当前系统是主系统，则更新主需求次数
                int mainReqCount = (int) systemInfoDict.get(systemName).get("main_req_count") + 1;
                systemInfoDict.get(systemName).put("main_req_count", mainReqCount);
                // 将主需求信息添加到系统信息中的需求信息列表的开头
                ((List<String>) systemInfoDict.get(systemName).get("demand_info")).add(0, "[主]" + demandNo + demandName);
            } else {
                // 如果当前系统不是主系统，则更新关联需求次数
                int relatedReqCount = (int) systemInfoDict.get(systemName).get("related_req_count") + 1;
                systemInfoDict.get(systemName).put("related_req_count", relatedReqCount);
                // 将关联需求信息添加到系统信息中的需求信息列表中
                ((List<String>) systemInfoDict.get(systemName).get("demand_info")).add(demandNo + demandName);
            }
        }

        // 创建节点
        for (String systemName : systemInfoDict.keySet()) {
            // 将系统名称作为节点添加到图中
            graph.addVertex(systemName);
        }

        // 创建边
        Map<String, Map<String, Integer>> edgeCounts = new HashMap<>();
        for (Map.Entry<String, Map<String, Object>> entry : demandInfoDict.entrySet()) {
            String mainSystem = (String) entry.getValue().get("main_system");
            List<String> relatedSystems = (List<String>) entry.getValue().get("related_systems");
            if (!mainSystem.isEmpty() && relatedSystems.size() > 1) {
                for (String system : relatedSystems) {
                    if (!system.equals(mainSystem)) {
                        // 统计边的数量
                        edgeCounts.computeIfAbsent(system, k -> new HashMap<>());
                        edgeCounts.get(system).put(mainSystem, edgeCounts.get(system).getOrDefault(mainSystem, 0) + 1);
                    }
                }
            }
        }

        for (Map.Entry<String, Map<String, Integer>> sourceEntry : edgeCounts.entrySet()) {
            String source = sourceEntry.getKey();
            for (Map.Entry<String, Integer> targetEntry : sourceEntry.getValue().entrySet()) {
                String target = targetEntry.getKey();
                // 根据边的数量添加边到图中
                for (int i = 0; i < targetEntry.getValue(); i++) {
                    graph.addEdge(source, target);
                }
            }
        }

        // 处理孤立节点
        for (String node : graph.vertexSet()) {
            if (graph.inDegreeOf(node) == 0 && graph.outDegreeOf(node) == 0) {
                System.out.println("孤立节点: " + node);
                // 为孤立节点添加自环边
                graph.addEdge(node, node);
            }
        }

        return graph;
    }

    /**
     * 将构建好的图导入到 Neo4j 数据库中。
     *
     * @param graph    构建好的图。
     * @param dataList 系统数据列表。
     */
    @Override
    public void importGraphToNeo4j(Graph<String, DefaultEdge> graph, List<SystemData> dataList) {
        // 创建 ObjectMapper 实例用于 JSON 序列化
        ObjectMapper objectMapper = new ObjectMapper();
        try (Session session = driver.session()) {
            session.writeTransaction(tx -> {
                // 删除数据库中现有的所有节点和关系
                tx.run("MATCH (n) DETACH DELETE n");

                // 存储系统信息
                Map<String, Map<String, Object>> systemInfoDict = new HashMap<>();
                // 存储需求维度的信息
                Map<String, Map<String, Object>> demandInfoDict = new HashMap<>();

                for (SystemData data : dataList) {
                    String systemName = data.getSystemName();
                    String demandNo = data.getDemandNo();
                    String demandName = data.getDemandTitle();
                    String changeContent = data.getChangeContent();
                    String isMainSystem = data.getIsMainSystem();
                    String systemLayer = data.getSystemLayer();
                    String systemArea = data.getSystemArea();
                    String systemBelongDepartment = data.getSystemBelongDepartment();
                    String systemManager = data.getSystemManager();
                    String systemNo = data.getSystemNo();
                    String reportDate = data.getReportDate();

                    // 需求维度
                    demandInfoDict.computeIfAbsent(demandNo, k -> new HashMap<String, Object>() {{
                        put("demand_name", demandName);
                        put("change_content", new ArrayList<String>());
                        put("main_system", "");
                        put("related_systems", new ArrayList<String>());
                    }});
                    if ("是".equals(isMainSystem)) {
                        demandInfoDict.get(demandNo).put("main_system", systemName);
                    }
                    ((List<String>) demandInfoDict.get(demandNo).get("change_content")).add(changeContent);
                    List<String> relatedSystems = (List<String>) demandInfoDict.get(demandNo).get("related_systems");
                    if (!relatedSystems.contains(systemName)) {
                        relatedSystems.add(systemName);
                    }

                    // 系统维度
                    systemInfoDict.computeIfAbsent(systemName, k -> new HashMap<String, Object>() {{
                        put("demand_no", new ArrayList<String>());
                        put("demand_info", new ArrayList<String>());
                        put("change_content", new ArrayList<String>());
                        put("change_count", 0);
                        put("main_req_count", 0);
                        put("related_req_count", 0);
                        put("system_layer", systemLayer);
                        put("system_area", systemArea);
                        put("system_belong_department", systemBelongDepartment);
                        put("system_manager", systemManager);
                        put("system_no", systemNo);
                        put("report_date", reportDate);
                    }});
                    ((List<String>) systemInfoDict.get(systemName).get("demand_no")).add(demandNo);
                    ((List<String>) systemInfoDict.get(systemName).get("change_content")).add(changeContent);
                    int changeCount = (int) systemInfoDict.get(systemName).get("change_count") + 1;
                    systemInfoDict.get(systemName).put("change_count", changeCount);
                    if ("是".equals(isMainSystem)) {
                        int mainReqCount = (int) systemInfoDict.get(systemName).get("main_req_count") + 1;
                        systemInfoDict.get(systemName).put("main_req_count", mainReqCount);
                        ((List<String>) systemInfoDict.get(systemName).get("demand_info")).add(0, "[主]" + demandNo + demandName);
                    } else {
                        int relatedReqCount = (int) systemInfoDict.get(systemName).get("related_req_count") + 1;
                        systemInfoDict.get(systemName).put("related_req_count", relatedReqCount);
                        ((List<String>) systemInfoDict.get(systemName).get("demand_info")).add(demandNo + demandName);
                    }
                    systemInfoDict.get(systemName).put("system_layer", systemLayer);
                    systemInfoDict.get(systemName).put("system_area", systemArea);
                    systemInfoDict.get(systemName).put("system_belong_department", systemBelongDepartment);
                    systemInfoDict.get(systemName).put("system_manager", systemManager);
                    systemInfoDict.get(systemName).put("system_no", systemNo);
                    systemInfoDict.get(systemName).put("report_date", reportDate);
                }

                // 批量导入节点
                StringBuilder createNodesQuery = new StringBuilder("UNWIND $nodes AS node CREATE (:系统 {name: node.name, status: node.status, ReqCount: node.requests_count, " +
                        "ReqCountStr: node.change_count, MainReqCount: node.main_req_count, " +
                        "RelatedReqCount: node.related_req_count, SysCount: node.system_count, info: node.info, isImportant: node.is_important, " +
                        "systemLayer: node.system_layer, systemArea: node.system_area, systemBelongDepartment: node.system_belong_department, " +
                        "systemManager: node.system_manager, systemNo: node.system_no, reportDate: node.report_date})");
                List<Map<String, Object>> nodes = new ArrayList<>();
                int childrenId = 1;
                for (String node : graph.vertexSet()) {
                    Map<String, Object> systemInfo = systemInfoDict.getOrDefault(node, new HashMap<>());
                    int changeCount = (int) systemInfo.getOrDefault("change_count", 0);
                    int mainReqCount = (int) systemInfo.getOrDefault("main_req_count", 0);
                    int relatedReqCount = (int) systemInfo.getOrDefault("related_req_count", 0);
                    String changeCountNew = changeCount + " (主: " + mainReqCount + " 关联: " + relatedReqCount + ")";
                    int status = new Random().nextInt(4) + 1;
                    int isImportant = graph.inDegreeOf(node) == 0 && graph.outDegreeOf(node) == 0 ? 1 : 0;
                    int systemCount = graph.degreeOf(node);

                    List<Map<String, Object>> infoList = new ArrayList<>();
                    List<String> demandNoList = (List<String>) systemInfo.get("demand_no");
                    List<String> demandInfoList = (List<String>) systemInfo.get("demand_info");
                    List<String> changeContentList = (List<String>) systemInfo.get("change_content");

                    for (int i = 0; i < demandInfoList.size(); i++) {
                        Map<String, Object> infoItem = new HashMap<>();
                        infoItem.put("id", demandNoList.get(i));
                        infoItem.put("label", demandInfoList.get(i));
                        List<Map<String, Object>> children = new ArrayList<>();
                        Map<String, Object> child = new HashMap<>();
                        child.put("id", childrenId++);
                        child.put("label", changeContentList.get(i));
                        children.add(child);
                        infoItem.put("children", children);
                        infoList.add(infoItem);
                    }

                    Map<String, Object> nodeData = new HashMap<>();
                    nodeData.put("name", node);
                    nodeData.put("status", status);
                    nodeData.put("requests_count", changeCount);
                    nodeData.put("change_count", changeCountNew);
                    nodeData.put("main_req_count", mainReqCount);
                    nodeData.put("related_req_count", relatedReqCount);
                    nodeData.put("system_count", systemCount);
                    try {
                        String infoJson = objectMapper.writeValueAsString(infoList);
                        nodeData.put("info", infoJson);
                    } catch (JsonProcessingException e) {
                        e.printStackTrace();
                        nodeData.put("info", "");
                    }
                    nodeData.put("is_important", isImportant);
                    nodeData.put("system_layer", systemInfo.get("system_layer"));
                    nodeData.put("system_area", systemInfo.get("system_area"));
                    nodeData.put("system_belong_department", systemInfo.get("system_belong_department"));
                    nodeData.put("system_manager", systemInfo.get("system_manager"));
                    nodeData.put("system_no", systemInfo.get("system_no"));
                    nodeData.put("report_date", systemInfo.get("report_date"));
                    nodes.add(nodeData);
                }
                tx.run(createNodesQuery.toString(), Values.parameters("nodes", nodes));

                // 批量导入边
                StringBuilder createEdgesQuery = new StringBuilder("UNWIND $edges AS edge MATCH (source:系统 {name: edge.source_name}), (target:系统 {name: edge.target_name}) " + 
                        "CREATE (source)-[:关联 {weight: edge.demand_no}]->(target)");
                List<Map<String, Object>> edges = new ArrayList<>();
                // 假设在遍历需求信息时构建边的数据
                for (Map.Entry<String, Map<String, Object>> entry : demandInfoDict.entrySet()) {
                    String demandNo = entry.getKey();
                    String mainSystem = (String) entry.getValue().get("main_system");
                    List<String> relatedSystems = (List<String>) entry.getValue().get("related_systems");
                    if (!mainSystem.isEmpty() && relatedSystems.size() > 1) {
                        for (String system : relatedSystems) {
                            if (!system.equals(mainSystem)) {
                                Map<String, Object> edgeData = new HashMap<>();
                                edgeData.put("source_name", system);
                                edgeData.put("target_name", mainSystem);
                                edgeData.put("demand_no", demandNo);
                                edges.add(edgeData);
                            }
                        }
                    }
                }
                tx.run(createEdgesQuery.toString(), Values.parameters("edges", edges));

                return null;
            });
        }
    }

    /**
     * 关闭 Neo4j 数据库驱动连接。
     */
    @Override
    public void close() {
        // 检查驱动实例是否存在，如果存在则关闭连接
        if (driver != null) {
            driver.close();
        }
    }
}
